package uns.fit.gis.upload;

import uns.fit.gis.httpconnection.MHttpConnItem;
import uns.fit.gis.httpconnection.MHttpConnUtils;
import uns.fit.gis.httpconnection.MHttpConnection;
import uns.fit.gis.httpconnection.MHttpConnectionHandler;

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 *
 * @author hoannguyenngoc
 */
public class PhotoUploader implements Runnable, MHttpConnectionHandler{

    public static String url1 = "http://hcmus-gps-locator.appspot.com/photo/upload";
    public static String url2 = "http://hcmus-gps-locator.appspot.com/photo/upload/part";
    public static int MAXIMUM_FAILED_REQUEST = 10;
    public static int PART_SIZE = 15 * 1024;
    
    private int curFailedRequests;
    private byte[] bytes;
    private String name;
    private String lat, lng;
    private int total, part;
    private String comment;
    private int id, session;
    private MHttpConnection conn;
    
    private PhotoUploaderListener listener;

    public void setListener(PhotoUploaderListener listener) {
        this.listener = listener;
    }
    
    public void run() {
        String str = "id=" + id + "&name=" + name + "&comment=" + MHttpConnUtils.MUrlEncoder(comment) +
                    "&total=" + total + "&lat=" + lat + "&lng=" + lng;
        MHttpConnItem item = new MHttpConnItem(-1, this, url1, false, true, str.getBytes());
        if (conn == null) {
            conn = new MHttpConnection();
            conn.addItem(item);
            conn.start();
        } else
            conn.addItem(item);
        
    }

    private String encodeBytes(int part) {
        if (part >= total)
            return null;
        int len = PART_SIZE;
        if (part == total - 1)
            len = bytes.length - part * PART_SIZE;
        String result = MHttpConnUtils.MBase64Encode(bytes, part * PART_SIZE, len, null);
        result = MHttpConnUtils.MUrlEncoder(result);
        System.out.println(result);
        return result;
    }
    
    private String getContent(String xml) {
        int idx1 = xml.indexOf("\">");
        int idx2 = xml.indexOf("</");
        if (idx1 == -1 || idx2 == -1)
            return xml.trim();
        else
            return xml.substring(idx1 + 2, idx2).trim();
    }
    
    public int HttpLoadCompleted(byte[] data, int errorCode, MHttpConnItem item) {
        if (errorCode != MHttpConnectionHandler.ERR_HTTP_COMPLETED || data == null) {  // fail or timeout
            System.out.println("HTTP failed");
            if (item.getItemID() == -1) { // head request 
                if (curFailedRequests < MAXIMUM_FAILED_REQUEST) {
                    curFailedRequests++;
                    this.run();  // retry
                } else
                    listener.uploadFailed();
            }
            else {  // upload photo piece request
                part = item.getItemID();
                if (part < total && curFailedRequests < MAXIMUM_FAILED_REQUEST) {
                    curFailedRequests++;
                    String str = "session=" + session + "&part=" + part + "&bytes=" + encodeBytes(part);
                    MHttpConnItem item1 = new MHttpConnItem(part, this, url2, false, true, str.getBytes());
                    conn.addItem(item1);
                } else
                    listener.uploadFailed();
            }
        } else { // receive response from server
            System.out.println(new String(data));
            boolean retry = false;
            if (item.getItemID() == -1) {  // head request 
                try {
                    session = Integer.parseInt(getContent(new String(data)));
                    if (session == -1)
                        retry = true;
                } catch (Exception exc) {
                    System.out.println("Session is not a valid number");
                    retry = true;
                }
                if (retry) {
                    if (curFailedRequests < MAXIMUM_FAILED_REQUEST) {
                        curFailedRequests++;
                        this.run();
                    } else
                        listener.uploadFailed();
                } else { // upload first photo piece request
                    System.out.println("Session = " + session);
                    String str = "session=" + session + "&part=0&bytes=" + encodeBytes(0);
                    MHttpConnItem item1 = new MHttpConnItem(0, this, url2, false, true, str.getBytes());
                    conn.addItem(item1);
                }
            }
            else { // upload photo piece request
                String response = getContent(new String(data));
                System.out.println("AFTER TRIM: " + response);
                if (!response.trim().equals("OK")) {   // last upload photo piece is damaged,...
                    part = item.getItemID();
                    if (part < total && curFailedRequests < MAXIMUM_FAILED_REQUEST) { // upload that photo piece again
                        curFailedRequests++;
                        String str = "session=" + session + "&part=" + part + "&bytes=" + encodeBytes(part);
                        MHttpConnItem item1 = new MHttpConnItem(part, this, url2, false, true, str.getBytes());
                        conn.addItem(item1);
                    } else
                        listener.uploadFailed();
                } else {
                    part = item.getItemID() + 1;
                    if (part < total) {
                        String str = "session=" + session + "&part=" + part + "&bytes=" + encodeBytes(part);
                        MHttpConnItem item1 = new MHttpConnItem(part, this, url2, false, true, str.getBytes());
                        conn.addItem(item1);
                    }
                    else if (part == total) // finish
                        listener.uploadFinished();
                    else
                        listener.uploadFailed();
                }
            }
        }
        return 0;
    }
    
    public void startUpload(int id, String name, String comment, String lat, String lng, byte[] bytes) {
        curFailedRequests = 0;
        this.id = id;
        this.name = name;
        this.comment = comment;
        this.lat = lat;
        this.lng = lng;
        this.bytes = bytes;
        this.total = bytes.length / PART_SIZE + (bytes.length % PART_SIZE == 0 ? 0 : 1);
        new Thread(this).start();
    }

//    public void next() {
//        if (part < total) {
//            String str = "session=" + session + "&part=" + part + "&bytes=" + encodeBytes(part);
//            MHttpConnItem item1 = new MHttpConnItem(part, this, url2, false, true, str.getBytes());
//            conn.addItem(item1);
//        }
//        else if (part == total) // finish
//            listener.uploadFinished();
//        else
//            listener.uploadFailed();
//    }
}
